{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.1.0\n",
      "sys.version_info(major=3, minor=6, micro=9, releaselevel='final', serial=0)\n",
      "matplotlib 3.1.2\n",
      "numpy 1.18.1\n",
      "pandas 0.25.3\n",
      "sklearn 0.22.1\n",
      "tensorflow 2.1.0\n",
      "tensorflow_core.python.keras.api._v2.keras 2.2.4-tf\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n将模型保存为 saveModel\\n'"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "import tensorflow as tf\n",
    "\n",
    "from tensorflow import keras\n",
    "\n",
    "print(tf.__version__)\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, tf, keras:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "'''\n",
    "将模型保存为 saveModel\n",
    "'''    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(5000, 28, 28) (5000,)\n",
      "(55000, 28, 28) (55000,)\n",
      "(10000, 28, 28) (10000,)\n"
     ]
    }
   ],
   "source": [
    "fashion_mnist = keras.datasets.fashion_mnist\n",
    "(x_train_all, y_train_all), (x_test, y_test) = fashion_mnist.load_data()\n",
    "x_valid, x_train = x_train_all[:5000], x_train_all[5000:]\n",
    "y_valid, y_train = y_train_all[:5000], y_train_all[5000:]\n",
    "\n",
    "print(x_valid.shape, y_valid.shape)\n",
    "print(x_train.shape, y_train.shape)\n",
    "print(x_test.shape, y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# x = (x - u) / std\n",
    "\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "\n",
    "scaler = StandardScaler()\n",
    "# x_train: [None, 28, 28] -> [None, 784]\n",
    "x_train_scaled = scaler.fit_transform(\n",
    "    x_train.astype(np.float32).reshape(-1, 1)).reshape(-1, 28, 28)\n",
    "x_valid_scaled = scaler.transform(\n",
    "    x_valid.astype(np.float32).reshape(-1, 1)).reshape(-1, 28, 28)\n",
    "x_test_scaled = scaler.transform(\n",
    "    x_test.astype(np.float32).reshape(-1, 1)).reshape(-1, 28, 28)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# tf.keras.models.Sequential()\n",
    "\n",
    "\"\"\"\n",
    "model = keras.models.Sequential()\n",
    "model.add(keras.layers.Flatten(input_shape=[28, 28]))\n",
    "model.add(keras.layers.Dense(300, activation=\"relu\"))\n",
    "model.add(keras.layers.Dense(100, activation=\"relu\"))\n",
    "model.add(keras.layers.Dense(10, activation=\"softmax\"))\n",
    "\"\"\"\n",
    "\n",
    "model = keras.models.Sequential([\n",
    "    keras.layers.Flatten(input_shape=[28, 28]),\n",
    "    keras.layers.Dense(300, activation='relu'),\n",
    "    keras.layers.Dense(100, activation='relu'),\n",
    "    keras.layers.Dense(10, activation='softmax')\n",
    "])\n",
    "\n",
    "# relu: y = max(0, x)\n",
    "# softmax: 将向量变成概率分布. x = [x1, x2, x3], \n",
    "#          y = [e^x1/sum, e^x2/sum, e^x3/sum], sum = e^x1 + e^x2 + e^x3\n",
    "\n",
    "# reason for sparse: y->index. y->one_hot->[] \n",
    "model.compile(loss=\"sparse_categorical_crossentropy\",\n",
    "              optimizer = \"sgd\",\n",
    "              metrics = [\"accuracy\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 55000 samples, validate on 5000 samples\n",
      "Epoch 1/10\n",
      "55000/55000 [==============================] - 5s 83us/sample - loss: 0.5439 - accuracy: 0.8070 - val_loss: 0.4037 - val_accuracy: 0.8572\n",
      "Epoch 2/10\n",
      "55000/55000 [==============================] - 4s 70us/sample - loss: 0.3959 - accuracy: 0.8579 - val_loss: 0.3668 - val_accuracy: 0.8744\n",
      "Epoch 3/10\n",
      "55000/55000 [==============================] - 4s 69us/sample - loss: 0.3583 - accuracy: 0.8708 - val_loss: 0.3473 - val_accuracy: 0.8768\n",
      "Epoch 4/10\n",
      "55000/55000 [==============================] - 4s 70us/sample - loss: 0.3335 - accuracy: 0.8790 - val_loss: 0.3486 - val_accuracy: 0.8724\n",
      "Epoch 5/10\n",
      "55000/55000 [==============================] - 4s 68us/sample - loss: 0.3135 - accuracy: 0.8859 - val_loss: 0.3294 - val_accuracy: 0.8818\n",
      "Epoch 6/10\n",
      "55000/55000 [==============================] - 4s 68us/sample - loss: 0.2975 - accuracy: 0.8914 - val_loss: 0.3281 - val_accuracy: 0.8780\n",
      "Epoch 7/10\n",
      "55000/55000 [==============================] - 4s 69us/sample - loss: 0.2839 - accuracy: 0.8977 - val_loss: 0.3212 - val_accuracy: 0.8802\n",
      "Epoch 8/10\n",
      "55000/55000 [==============================] - 4s 69us/sample - loss: 0.2724 - accuracy: 0.9007 - val_loss: 0.3115 - val_accuracy: 0.8852\n",
      "Epoch 9/10\n",
      "55000/55000 [==============================] - 4s 70us/sample - loss: 0.2615 - accuracy: 0.9052 - val_loss: 0.3237 - val_accuracy: 0.8838\n",
      "Epoch 10/10\n",
      "55000/55000 [==============================] - 4s 69us/sample - loss: 0.2515 - accuracy: 0.9096 - val_loss: 0.3219 - val_accuracy: 0.8814\n"
     ]
    }
   ],
   "source": [
    "history = model.fit(x_train_scaled, y_train, epochs=10,\n",
    "                    validation_data=(x_valid_scaled, y_valid))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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sa8Cy621txtj5gBPANMHOm5BqBFatsLiy52rpw85GXyB/W6IiIhIPhhKj/k4YIO1diOAMeZB4HwgPZgtUJqYLwN2DHbQjqLpcH3P5yWKiIiMbcZaO3ABYy4EzrbWXpFYvgQ43lp7XVqZicCfgQqgCHi/tfbVPo51FXAVQE1NzeLly5ePVDuypr29neLi4mxXY1jyoQ2QH+3IhzaA2pFL8qENkB/tWLJkyavW2mMGKzdSF39dDNxtrf2hMeZE4D5jzDxrbTy9kLV2GbAMYObMmba2tnaE3j576urqGO3tyIc2QH60Ix/aAGpHLsmHNkD+tGMohnKj6O3A1LTlKYl16f4FWA5grX0e8APVI1FBERGRsWQowfwycIQxZoYxxgd8HHisR5mtwBkAxpjZOMHcMJIVFRERGQsGDWZrbRS4DngSWItz9fVqY8w3jTHnJYr9O3ClMeZ14LfAZXawk9ciIiLSy5DOMSd+k/xEj3VfT5tfA5w8slUTEREZe/QwYhERkRyiYBYREckhCmYREZEcomAWERHJIQpmERGRHKJgFhERySEKZhERkRyiYBYREckhCmYREZEcomAWERHJIQpmERGRHKJgFhERySEKZhERkRyiYBYREckhCmYREZEcomAWERHJIQpmERGRHKJgFhERySEKZhERkRyiYBYREckhCmYREZEcomAWERHJIQpmERGRHKJgFhERySEKZhERkRyiYBYREckhCmYREZEcomAWERHJIQpmERGRHKJgFhERySEKZhERkRyiYBYREckhCmYREZEcomAWERHJIQpmERGRHKJgFhERySEKZhERkRyiYBYREckhCmYREZEcomAWERHJIQpmERGRHKJgFhERySEKZhERkRyiYBYREckhCmYREZEcMqRgNsacbYx52xizwRhzYz9lPmaMWWOMWW2MeWBkqykiIjI2eAYrYIxxA7cBZwL1wMvGmMestWvSyhwBfBk42VrbbIwZd6AqLCIiks+G0mM+Dthgrd1orQ0DDwLn9yhzJXCbtbYZwFq7e2SrKSIiMjYMJZgnA9vSlusT69IdCRxpjHnWGPOCMebskaqgiIjIWGKstQMXMOZC4Gxr7RWJ5UuA462116WVeRyIAB8DpgDPAPOttS09jnUVcBVATU3N4uXLl49gU7Kjvb2d4uLibFdjWPKhDZAf7ciHNoDakUvyoQ2QH+1YsmTJq9baYwYrN+g5ZmA7MDVteUpiXbp64EVrbQTYZIxZDxwBvJxeyFq7DFgGMHPmTFtbWzuEt89tdXV1jPZ25EMbID/akQ9tALUjl+RDGyB/2jEUQxnKfhk4whgzwxjjAz4OPNajzP8AtQDGmGqcoe2NI1hPERGRMWHQYLbWRoHrgCeBtcBya+1qY8w3jTHnJYo9CTQZY9YAK4AvWGubDlSlRURE8tVQhrKx1j4BPNFj3dfT5i3w+cRLRERE9pPu/CUiIpJDFMwiIiI5RMEsIiKSQxTMIiIiOUTBLCIikkMUzCIiIjlEwSwiIpJDFMwiIiI5RMEsIiKSQ7IWzA2dlq5wLFtvLyIikpOyFswdUctHb3+O+ubObFVBREQk52QtmMcHDNuaOznvZ8/ywkY970JERASyGMyFHsMfrj2ZioCXT935Ivc9vxnnWRgiIiJjV1Yv/jq0pphHrz2Z046s4Wt/WM2Xf/8moajOO4uIyNiV9auyS/1efvnPx3DdksN58OVtfOKXL7K7LZjtaomIiGRF1oMZwOUy/MdZM7ntE0ezZsdezvvps7xR35LtaomIiBx0ORHMSR9cMJFHrjkJt8tw4R3P8/vX6rNdJRERkYMqp4IZYM6kUv73+vdx9LRyPr/8dW55fA3RWDzb1RIRETkoci6YASqLfNz3L8dz2UnTuXPlJi6/+2VaOsPZrpaIiMgBl5PBDOB1u7j5vLl8/6MLeHHjHs6/7VnW72rLdrVEREQOqJwN5qSPHTuV3151Ap3hGB++7VmeXL0z21USERE5YHI+mAEWH1LB/173Pg4fV8y/3vcqP3nqHeJx3YxERETyz6gIZoAJZX4e+tcT+ejRU/jxU+u55v5XaQ9Fs10tERGRETVqghnA73Xzg4sW8LVz5/DU2t185OfPsqWpI9vVEhERGTGjKpgBjDH8y/tmcM/lx7Frb4jzfvYsK99pzHa1RERERsSoC+ak9x1RzWPXncyEUj//fNeL3Pn3jXoIhoiIjHqjNpgBDqkq4vefOYkPzJnALX9cy7//7nWCET0EQ0RERq9RHcwARQUefv7Jo/n8mUfy+9e2s/QXz7OzVQ/BEBGR0WnUBzM4D8G44Ywj+MUli9mwu50P/Wwlr25pzna1RERE9lleBHPSWXMn8Oi1JxPwubl42Qs89PLWbFdJRERkn+RVMAMcOb6EP1x7MscfWsmXHnmTb/zhLSJ6CIaIiIwSeRfMAOUBH7++7FiuPGUG9zy/hUt+9SJN7aFsV0tERGRQeRnMAB63i698cA4/XrqQ17a2cN7PnmX1jtZsV0tERGRAeRvMSR9eNIWHrz6RuLVcePvzPP7GjmxXSUREpF95H8wAC6aU84frTmbOpFKue+AffP9P64jpIRgiIpKDxkQwA4wr8fPAlcdz8XFT+Xndu1x57yvsDUayXS0REZEMYyaYAQo8br7z4fl864J5PLO+gQtue5Z3G9qzXS0REZGUMRXM4DwE45ITDuH+K46npTPCBT97lhXrdme7WiIiIsAYDOak4w+t4rHrTmZqZYBP3/Myt9e9q4dgiIhI1o3ZYAaYUhHgkWtO4oPzJ/K9P63jhgdX0RXWQzBERCR7xnQwAxT63Pz04kV86exZPP7GDi684znqmzuzXS0RERmjxnwwg3Pe+Zraw7jr0mPZuqeT8372LC9sbMp2tUREZAxSMKdZMmsc/3PtyZQHvHzqzhe574UtOu8sIiIHlYK5h8Nqivmfa0/m1CNr+Nr/vMVNj75JOKqHYIiIyMGhYO5Dqd/LL//5GK5dchi/fWkbF//yBXa3BbNdLRERGQOGFMzGmLONMW8bYzYYY24coNxHjTHWGHPMyFUxO9wuwxfOmsXPPrGINTv2ct5Pn+WN+pZsV0tERPLcoMFsjHEDtwHnAHOAi40xc/ooVwJ8FnhxpCuZTecumMTD15yI22W46I7nefQf9dmukoiI5LGh9JiPAzZYazdaa8PAg8D5fZT7FvA9YEhjvnuie3hw3YO82fAmoVhuPyt57qQyHrvuZBZNK+dzD73Ot/+4hmhM551FRGTkeYZQZjKwLW25Hjg+vYAx5mhgqrX2j8aYLwzljbviXXz7xW87lTAejqg4gjlVc5hbPZc5VXM4svxIvG7v0FpxEFQVF3DfvxzPLY+v4Zd/38S6nW389OJF2a6WiIjkGTPYz4GMMRcCZ1trr0gsXwIcb629LrHsAp4GLrPWbjbG1AH/Ya19pY9jXQVcBVBTU7P4jgfuYFt4G1tDW9kadl6dcefmHh48TPJNYppvGtN805haMJWJ3om4jXvEGr+//lYf4d7VYaoKDadNiDN7XCFTS114XSbbVdsv7e3tFBcXZ7saw5YP7ciHNoDakUvyoQ2QH+1YsmTJq9baQa/BGkownwjcbK09K7H8ZQBr7X8mlsuAd4HkY5omAHuA8/oK56SZM2fat99+O2OdtZbt7dtZ3bSa1U2rWdO0hjWNa2iLtAFQ4C5gZuVM5lQ6Peu5VXOZUTYDj2soHf+R9eqWZj774D+ob+4CwOs2zJpQyvwpZSycUsaCKeUcMa4Yjzv3L3yvq6ujtrY229UYtnxoRz60AdSOXJIPbYD8aIcxZkjBPJREexk4whgzA9gOfBz4RHKjtbYVqE574zr66TEPodJMKZnClJIpnDX9LADiNk59W70T1o1OYD/27mM8+PaDABR6CplVOYu5Vc4Q+NyquRxSeghu14HtWS8+pIK/f3EJj/xpBUVTZvN6fStv1Lfwv6t28MCLWwHwe13Mm1SWCOtyFkwpY3pVEa5R2rMWEZEDb9BgttZGjTHXAU8CbuAua+1qY8w3gVestY8dyAq6jItppdOYVjqNc2acAzhhvWXvllRYr2lawyPvPMJv1v4GgIAnwOyq2cytcnrVc6vnMrVkKi4zsr1XYwzVhS5q50/knPkTnbrFLZubOnijvpXX61t4o76V3760lV8/uxmAEr+HBVPKmD+53OlZTy1nUpkfYxTWIiIytB4z1tongCd6rPt6P2Vrh1+tgbmMixllM5hRNoNzDz0XgFg8xqbWTRnD4A+9/VDqiu9ib3GqRz2n2plOKZ4y4oHochkOrSnm0JpiLlg0GYBoLM47u9t5o76F1+tbebO+lV+t3Egk5pxGqC72MX+yM/y9cKozrS4uGNF6iYjI6HDwT84eIG6Xm8MrDufwisM5/3Dn11zReJR3W95lTdOaVO/6N2t/QyQeAaDUV5rqUSdDe2LRxBEPa4/bxeyJpcyeWMrSY511wUiMdTvbeCPRq36jvoW69Q0kT/lPKvOzYEo5C6Y6w+DzJpdRVpg7V6mLiMiBkTfB3BePy8PMypnMrJzJh4/4MACRWIR3Wt7JCOu737qbqI0CUFFQkepRJ89bjw+MH/Gw9nvdHDW1nKOmlqfWdYSivLW9lTe3t6bOWf9p9c7U9hnVRSxIXFi2cEoZcyaVEvDl9V+hiMiYM+Y+1b1uL3Oq5jCnag4XciEAoViId5rfSV1ctrppNb/a8StiNgZAlb8qdRV4soddXVg90Nvsl6ICD8cfWsXxh1al1rV0hnlze6tzznpbCy9u3MMfVu0AwGXgyPElaWFdzswJJfg8uX8luIiI9G3MBXNfCtwFzKuex7zqeal1wWiQt5vfToX1mqY1rNy+krh17vg1LjCOOVVzMC2GLau3MC4wjnGBcYwPjGdcYBw+t29E6lYe8HHKETWcckRNat3uvcHU8Pfr9a38Zc0ulr/i3CrU53Yxe2KJMwyeCOzDxxXj1pXgIiKjgoK5H36Pn4U1C1lYszC1rjPSybo961LD4Gua1lDfXs+KV1b02r+ioMIJ6qLxGaGdDO5xgXGU+kr3a4h8XKmf98/x8/454wHn99/1zV1pYd3Co//Yzn0vbAEg4HMzb1KZE9RTy1kwuYxDqgK6ElxEJAcpmPdBwBvg6PFHc/T4o1PrVqxYweKTF7O7Yze7O3ezq3MXuzp3sbuze/mtxrfYE9zT63h+tz8juHuG9/jAeKoKqwa9gYoxhqmVAaZWBvjggu6fbW1s7Mi4uOy+F7YQWrkJgLJCb6JHXQbNUWp2tHJIVRHFBfpfQkQkm/QpPEzGGEp9pZT6Sjm84vB+y4VjYRq6GtjVsavPAF+1exW7OncRjUcz9nMZF9X+6kF73wFvIHM/l+HwccUcPq6Yjxw9BYBILM76XW28Wd99cdkv/raRaNxy26qVAFQV+ZhWFeCQygDTqooSU2e5pqRAvWwRkQNMwXyQ+Nw+JhdPZnLx5H7LxG2c5mBzRm87Pbw3t27mpfdeSt2iNF2Jt2TA3ve4wDgq/BXMnVTG3EllfPw4Z79gJMZD/1dHzYw5bGnqZOueDrY0dfLy5mYee30H8bQ7thZ63UxLC+pDqpzwnlYZYEpFId5RcPtREZFcp2DOIS7joqqwiqrCKmZXze63XGekMxXcGdNEb3xD8wYag42pC9WSvC5vr+AeFxjHTtdOKgIdTCq0TJgc51gscRsnEouxpyNEU0coNW3uDLG6PcSzDSEisTjGOMltjKXE76Y84KGs0EtpoYeyQjclfjclhR68boO1znHjxLHWYhPvE7eZy6npEMskj9fR3MFrr76W8WUkeTrA69JvwEVkdFAwj0IBb4DpZdOZXja93zLReJTGrsZ+e9/r9qzjb9v+RjCWeHz2yn2oQBG4i5z7s6YLAbuAXWEgDLbFAM4r+Z/LuDDG4DYu3C4XbuPG43LWpW9PzruMq9/1QEaZXcFdvL7m9dQNZJIMhqrCKmoKazJCO/3LybiicZR4SzRULyJZp2DOUx6XhwlFE5hQNKHfMtZa9ob38udn/swJJ5zQKwyNMRnB2FcYJsu4cGWUbw9FE0Pjnakh8uT8jpaujCFyv9flDJFXFnFIVWKIvDKQGCIPDPl32XV1dZx22mk0hzJPByTnd3fuZkfHDlY1rKIl1NJr/0JPYUZoZwS3et8icpAomMcwYwxlBWXUeGuYWjJ1RI9d4vcyb3IZ8yaX9doWjsbZ3tLFlqbusE6G98oNDQQj3UPwLgMTywrTAruoO7irApT6M0PSGEOlv5JKfyWzKmf1W79QLJQR2D1DfNXuVezu3N1v77tncGf0xtX7FpFhUDDLQSuN2JkAAB8JSURBVOfzuJhRXcSM6qJe26y1NLSF2JLsaTd1pOafXL2LPR3hjPIVAW/q6vHY3jBbCzYzodTPxLJCJpT5qSry9fmYzQJ3AVNLpg74hcRa22/ve1fnLra3b+cfu/9Ba6i1177qfYvI/lIwS04xxjCu1M+4Uj/HTq/stb0tGGFLUyfb9nR2h/eeDl7b2sx7LRH+uGl1Rnmv2zC+1M/EMj8TygqdaWrZCfCakoI+74w21N53MBqkobMhc9i8a/d+9b7bWtrY8OaGIZ1WyDgv3996Y3DRe/1A5+77PXWRdqz+1ifr2hxtpjXUSoG7gAK3fmYnsi8UzDKqDDRE/vSKFcxbfCI79wZ5rzXIztbktIv3WoO8Ud/Ck6uDhKOZV6u7XYZxJQWJoPYzobQwLbid6bgSf7/nuv0eP1NLpzK1tP/ed9zGaQm1DK33/drw/oxyxdcfdJ4MazD4PX4K3AX4PX78bn9qWuApoNBd2Pf2fuYL3AUUegq79/cUpvbVCITkAwWz5A1XWm97wZS+y1hrae6M8F5rV1pwJ6Z7u1i3s40V6xroisQy9jMGqosLevS4MwN8fKkfv7fnterJurmG1Pv+64q/csqpp3T/RCzt52LA4OsTPx/r8+dm/f0MbQjH6vc9sN0/g0s71uq1qznksEMIxoIEo0FCsRBd0a7UfDAapCvWRSgaojXUSjAa7FV2f3iMhwJPQUb4Z4R52nzqi0CPLwvpXxo2hTYxtWUqRd4iirxFBDwB3K6+/45lcNZauqJd7A3vdV4hZ9oaau21rud8MBzE96AvNVLjMs6vOtKXkxeiulyu1ChOv+X6euHC7XL3e5yer0GPmzieweA2Q///RsEsY4oxhsoiH5VFPuZO6t3rhsTV6sFoIrC7A3xXoie+pamTFzY2sTcY7bVvZZGvx1B5d4Anh9SLBrjtqdu4R+wBKNlUXl9O7Zza/d7fWks4HnYCPNrVHeZp88kgz5hPm4aiIYKx7n32hveyq3NXr/17nmLo6Ud/+FHGcsATSAV1sbe4e95XTMAToNhX3Pf2tPkibxGFnsJRO8QfjAYzAzU9TPtbH9pLa7i1190N0xkMpQWlqbsplvpKmVg8kVJfKbvf282ESROw1hKzMSyWWDyWujdCPB5PfWGM27hTJlk2MU1ui8ajqflUWfouO9Dx+iyb9mV2fymYRXowxlBW6KWs0MvMCSX9lusIRdm5t/eQeXL5H9tael2sBlDi93QHdmnmkPm2tjhN7SHKA74x/UQwY0zq/HRZQd9foEZKLB5L9dLTe/PBaJAXXnuBw2YdRnuknY5IBx2RDtoj7XRGOmmPtKfm97TvoSPckSqXfGTsQFzGRZGniCJf79DuGegBb4Bib3G/4b8/X+ZCsVBGcPYXpn31aMPx3v9fJxkMxb7i7nAtKGV8YHxm4BaUUuYr67Wu2Fucuoahp7q6OmpPqN3ndmZDclSqZ3gXX1Y8pP0VzCL7qajAw2E1xRxW0/8/tmAklupp9wrwvUHWvreXxvYQNu133V979ilcBiqLCqgu9lFdXEBVj2n3+gKqinz9DqHL4NwuNwFXoNf95gHaCtuonVG7T8ez1hKKhTICPD3UO8IddEQ7aA93r09uaw+3s7NjZ2rfjkgHFjvoe3pd3n5DvbGxkUf++kivAA7FQgMes8RbkhGch5UflhGi6dMyX1lGuI714f70Cyr3h4JZ5ADye90cUlXEIVW9fxqWFInF2d0WYmdrF3997jXGH3I4je0hGtvDNLaHaGoPsXVrJ03tITrCfffESgo8VJc4Id1fgFcX+6gqLqDU7xm1Q6ijgTEmde6awuEdK27jdEW7eoV6eu88ta1Hj74p2MTWtq20Bduo6aihtKCU6aXTew0V99V7LfYVD/pUOzlw9CcvkmVet4vJ5YVMLi+kbZOH2pOm91u2MxylKRXYiWlHmIY2Z9rYFmJjYzsvbQ7T3BnO6Ikn+dyuXj3wqmIfNenLRQVUl/ioDPjw6OEkWeMyrlTvdxzj9usYdXV11NbWjmzF5IBSMIuMIgGfh0Clh6mVvYdde4rG4uzpDPcK8vSeeGN7mPU722hsDxOO9b5gxRioCPgG7Yk76woo9I3tIUyRkaBgFslTHreLcSXOb7AHY62lLRSlMa3n3ZiYNnWEaGwL09QRYvUO55x4Wx9XpAMEfG6qiwvwxILcs+klKgI+ygM+Kou8lAd8VAR8VAQS80VeKgI6Py7Sk4JZRDDGUOr3Uur3cmjN4OWDkRh7Orp74g3pQ+vtITZs2+X0xne109IZ7vfcODjP+U4P6/JEeFckg7yPUNd5cslnCmYR2Wd+r5tJ5YVMKu/76ibnvOb7UsuhaIzWzgjNnRGaO8O0dIbZ09E939wZSU3XvreX5o4wrV2RjKeQpXO7DOWFXiqK0nrgiTBPzRdlhnl5wItX58tlFFAwi8gBV+BxM67UzbjSwYfVk+Jxy95g7zB3AjwtzDsibNvTyRv1zrqet1xNV1LgobzIS2VagJf36pkneutFPrqizp3N1DuXg0nBLCI5yeUyiZ6ujxn0/3OzdNZauiIxJ8w7wrQkQr05EeA9e+gbG9tp6YjQFur/blSuvz5BaaEzzF9a6EkN+ZcVpi33nE8rG/C5FeyyTxTMIpI3jDHOles+D5P7GWbvSyQWpyVtON0J8jD/WP02NZOmsTcYYW9XhL3BKHu7ImxsbGdvV5S9wQidA5w/B/C4TCKsPb0Dvo/1Zal5Z+r3uhTsY4yCWUTGPK/bRU1JATUlBRnrJ3RupLZ25oD7RmLxjNB2QjyaFuY9l51buSa3BSMD31fZ6zb9hnhpRoh3L5elBb/t68fsktMUzCIiw+B1u5xboxYXDF64D6FojLZUqPcO99auSK9tO1q6UsuhAc6pA3gMlK38C6WFXkr8HudV4AR7id9ZV+pPbuvuzSeXS/weXTR3kCmYRUSyqMDjpqDY+f33/ghGEsGe6JG39gjxt97eSMW4CewNRmkLRmgLRtm9t522xPJAP2VLKvS6nQAvTAvwtGnv0O9eLi30Uuzz4BrDD2XZVwpmEZFRzO914/e6ew3DJ9VRT23t/H73j8bitIeiaeHeHeB7E9Oey61dEer3dKbCfrBeuzFQ7OsR4GnhPlDoJ3vxY2lIXsEsIjKGedyu1NXv+ys5HJ8M8Z7hvreP9bvbgmzY3b0c7e9H6wkuAyXP/JniAo/z8ndPS3qsK/F7KC7w9lh2thf5PDn/SFUFs4iIDMtwh+OTP3NLBntrWoAnw3312+9SNWEybcEo7aEI7aEoLZ1htjV30h6M0h6KDnqFfFKRz50W7N5ewd475NO/BHQHvs9zYM6951QwRyIR6uvrCQaD2a7KkJWVlbF27dpsV2NY+muD3+9nypQpeL3eLNRKRMaK9J+5je/nJjR1dhu1tXMHPE4sbmkPOSHdngrwWGq+LZi+LUpb2nxDWygxpO+E/iAdeAB8HpcT6mnhnd47Ly7wZgT7UOVUMNfX11NSUsL06dNHze/22traKCkpyXY1hqWvNlhraWpqor6+nhkzZmSpZiIiQ+d2GcoKnZu/DEeyB98ezAzv7mCP9Ar2ZNkdLcHUl4O2YIRIbN/PjedUMAeDwVEVyvnMGENVVRUNDQ3ZroqIyEGV3oPfv6dgdwtFY6nwnv69oe2TU8EMKJRziP4uRESGJ3n+fV9+565fjfdQXFyc7SqIiMgYpmAWERHJIQrmflhr+cIXvsC8efOYP38+Dz30EADvvfcep556KkcddRTz5s3jueeeIxaLcdlll6XK/vjHP85y7UVEZLTKuXPMSf/vf1ezZsfeET3mnEmlfONDA19un/T73/+eVatW8frrr9PY2Mixxx7LqaeeygMPPMBZZ53FV77yFWKxGLt27WLVqlVs376dt956C4CWlpYRrbeIiIwdORvM2bZy5Uouvvhi3G4348eP57TTTuPll1/m2GOP5dOf/jSRSIQLLriAww47jMLCQjZu3Mj111/PBz/4QT7wgQ9ku/oiIjJK5WwwD7Vne7CdeuqpPPPMM/zxj3/ksssu45prruFf//Vfef3113nyySe54447WL58OXfddVe2qyoiIqOQzjH345RTTuGhhx4iFovR0NDAM888w3HHHceWLVsYP348V155JVdccUVqqDsej/PRj36UW265hddeey3b1RcRkVEqZ3vM2fbhD3+Y559/noULF2KM4fvf/z4TJkzgnnvu4dZbb8Xr9VJcXMzPf/5ztm/fzuWXX0487jxh5T//8z+zXHsRERmthhTMxpizgZ8AbuBOa+13e2z/PHAFEAUagE9ba7eMcF0Pivb2dsC5ucatt97KrbfemrH90ksv5dJLL00tJ29nqV6yiIiMhEGHso0xbuA24BxgDnCxMWZOj2L/AI6x1i4AHga+P9IVFRERGQuGco75OGCDtXajtTYMPAicn17AWrvCWtuZWHwBmDKy1RQRERkbjLUDP/nCGHMhcLa19orE8iXA8dba6/op/zNgp7X2lj62XQVcBVBTU7N4+fLlGdvLyso4/PDD96cdWROLxXC73dmuxrAM1IYNGzbQ2tp6kGu0f9rb20f9LVXzoQ2gduSSfGgD5Ec7lixZ8qq19pjByo3oxV/GmE8BxwCn9bXdWrsMWAYwc+ZMW1tbm7F97dq1o+4Rivn62Mckv9/PokWLDnKN9k9dXR09/58abfKhDaB25JJ8aAPkTzuGYijBvB2YmrY8JbEugzHm/cBXgNOstaGRqZ6IiMjYMpRzzC8DRxhjZhhjfMDHgcfSCxhjFgG/AM6z1u4e+WqKiIiMDYMGs7U2ClwHPAmsBZZba1cbY75pjDkvUexWoBj4nTFmlTHmsX4OJyIiIgMY0jlma+0TwBM91n09bf79I1yvvBeNRvF4dH8XERHJpFty9uGCCy5g8eLFzJ07l2XLlgHwpz/9iaOPPpqFCxdyxhlnAM5Vgtdccw3z589nwYIFPPLIIwAZVw4+/PDDXHbZZQBcdtllXH311Rx//PF88Ytf5KWXXuLEE09k0aJFnHTSSbz99tuAc5X0f/zHfzBv3jwWLFjAT3/6U55++mkuuOCC1HH/8pe/8OEPf/hg/HGIiMhBlLtdtv+7EXa+ObLHnDAfzvnuoMXuuusuKisr6erq4thjj+X888/nyiuv5JlnnmHGjBns2bMHgG9961uUlpby5ptOPZubmwc9dn19Pc899xxut5u9e/fy97//HY/Hw1NPPcVNN93EI488wrJly9i8eTOrVq3C4/GwZ88eKioq+MxnPkNDQwM1NTX8+te/5tOf/vTw/jxERCTn5G4wZ9F///d/8+ijjwKwbds2li1bxqmnnsqMGTMAqKysBOCpp57izjvvTO1XUVEx6LEvuuii1G+GW1tbufTSS3nnnXcwxhCJRFLHvfrqq1ND3cn3u+SSS/jNb37D5ZdfzvPPP8+99947Qi0WEZFckbvBPISe7YFQV1fHU089xfPPP08gEKC2tpajjjqKdevWDfkYxpjUfDAYzNhWVFSUmv/a177GkiVLePTRR9m8efOgv9G7/PLL+dCHPoTf7+eiiy7SOWoRkTykc8w9tLa2UlFRQSAQYN26dbzwwgsEg0GeeeYZNm3aBJAayj7zzDP55S9/mdo3OZQ9fvx41q5dSzweT/W8+3uvyZMnA3D33Xen1p955pn84he/IBqNZrzfpEmTmDRpErfccguXX375yDVaRERyhoK5h7PPPptoNMrs2bO58cYbOeGEE6ipqWHZsmV85CMfYeHChSxduhSAr371q7S0tDBv3jwWLlzIihUrAPjud7/Lueeey0knncTEiRP7fa8vfvGLfPnLX2bRokWpEAa44oormDZtGgsWLGDhwoU88MADqW2f/OQnmTp1KrNnzz5AfwIiIpJNGgvtoaCggP/7v//rc9s555yTsVxcXMwvfvGLXrezvPDCC7nwwgt77Z/eKwY48cQTWb9+fWr5lluc24t7PB5+9KMf8aMf/ajXMVauXMmVV145pLaIiMjoo2AeRRYvXkxRURE//OEPs10VERE5QBTMo8irr76a7SqIiMgBpnPMIiIiOUTBLCIikkMUzCIiIjlEwSwiIpJDFMwiIiI5RME8DOlPkepp8+bNzJs37yDWRkRE8oGCWUREJIfk7O+Yv/fS91i3Z+gPjhiKWZWz+NJxX+p3+4033sjUqVO59tprAbj55pvxeDysWLGC5uZmIpEIt9xyC+eff/4+vW8wGOSaa67hlVdeSd3Va8mSJaxevZrLL7+ccDhMPB7nkUceYdKkSXzsYx+jvr6eWCzG1772tdQtQEVEJP/lbDBnw9KlS/m3f/u3VDAvX76cJ598khtuuIHS0lIaGxs54YQTOO+88zKeIDWY2267DWMMb775JuvWreMDH/gA69ev54477uCzn/0sn/zkJwmHw8RiMZ544gkmTZrEH//4R8B50IWIiIwdORvMA/VsD5RFixaxe/duduzYQUNDAxUVFUyYMIHPfe5zPPPMM7hcLrZv386uXbuYMGHCkI+7cuVKrr/+egBmzZrFIYccwvr16znxxBP59re/TX19PR/5yEc44ogjmD9/Pv/+7//Ol770Jc4991xOOeWUA9VcERHJQTrH3MNFF13Eww8/zEMPPcTSpUu5//77aWho4NVXX2XVqlWMHz++1zOW99cnPvEJHnvsMQoLC/mnf/onnn76aY488khee+015s+fz1e/+lW++c1vjsh7iYjI6JCzPeZsWbp0KVdeeSWNjY387W9/Y/ny5YwbNw6v18uKFSvYsmXLPh/zlFNO4f777+f0009n/fr1bN26lZkzZ7Jx40YOPfRQbrjhBrZu3cobb7zBrFmzqKys5FOf+hTl5eXceeedB6CVIiKS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\n",
      "text/plain": [
       "<Figure size 576x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_learning_curves(history):\n",
    "    pd.DataFrame(history.history).plot(figsize=(8, 5))\n",
    "    plt.grid(True)\n",
    "    plt.gca().set_ylim(0, 1)\n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(history)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10000/10000 [==============================] - 0s 37us/sample - loss: 0.3594 - accuracy: 0.8698\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[0.3593831724584103, 0.8698]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.evaluate(x_test_scaled, y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /home/ubuntu/environment/tf_py3/lib/python3.6/site-packages/tensorflow_core/python/ops/resource_variable_ops.py:1786: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "If using Keras pass *_constraint arguments to layers.\n",
      "INFO:tensorflow:Assets written to: ./keras_saved_graph/assets\n"
     ]
    }
   ],
   "source": [
    "## 将模型保存为 SavedModel\n",
    "tf.saved_model.save(model, \"./keras_saved_graph\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "OSError",
     "evalue": "[Errno 12] Cannot allocate memory",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mOSError\u001b[0m                                   Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-12-4bd77ead8cc4>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mget_ipython\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msystem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'saved_model_cli show --dir ./keras_saved_graph --all'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/IPython/core/interactiveshell.py\u001b[0m in \u001b[0;36msystem_piped\u001b[0;34m(self, cmd)\u001b[0m\n\u001b[1;32m   2444\u001b[0m         \u001b[0;31m# a non-None value would trigger :func:`sys.displayhook` calls.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2445\u001b[0m         \u001b[0;31m# Instead, we store the exit_code in user_ns.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2446\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0muser_ns\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'_exit_code'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msystem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvar_expand\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcmd\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdepth\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   2447\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2448\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0msystem_raw\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcmd\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/IPython/utils/_process_posix.py\u001b[0m in \u001b[0;36msystem\u001b[0;34m(self, cmd)\u001b[0m\n\u001b[1;32m    154\u001b[0m                 \u001b[0mchild\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpexpect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mspawnb\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'-c'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcmd\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Pexpect-U\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    155\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 156\u001b[0;31m                 \u001b[0mchild\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpexpect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mspawn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'-c'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcmd\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# Vanilla Pexpect\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    157\u001b[0m             \u001b[0mflush\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstdout\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mflush\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    158\u001b[0m             \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/pexpect/pty_spawn.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, command, args, timeout, maxread, searchwindowsize, logfile, cwd, env, ignore_sighup, echo, preexec_fn, encoding, codec_errors, dimensions, use_poll)\u001b[0m\n\u001b[1;32m    203\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'<pexpect factory incomplete>'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    204\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 205\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_spawn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcommand\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpreexec_fn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdimensions\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    206\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0muse_poll\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0muse_poll\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    207\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/pexpect/pty_spawn.py\u001b[0m in \u001b[0;36m_spawn\u001b[0;34m(self, command, args, preexec_fn, dimensions)\u001b[0m\n\u001b[1;32m    302\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    303\u001b[0m         self.ptyproc = self._spawnpty(self.args, env=self.env,\n\u001b[0;32m--> 304\u001b[0;31m                                      cwd=self.cwd, **kwargs)\n\u001b[0m\u001b[1;32m    305\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    306\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mptyproc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpid\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/pexpect/pty_spawn.py\u001b[0m in \u001b[0;36m_spawnpty\u001b[0;34m(self, args, **kwargs)\u001b[0m\n\u001b[1;32m    313\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_spawnpty\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    314\u001b[0m         \u001b[0;34m'''Spawn a pty and return an instance of PtyProcess.'''\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 315\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mptyprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mPtyProcess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mspawn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    316\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    317\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/ptyprocess/ptyprocess.py\u001b[0m in \u001b[0;36mspawn\u001b[0;34m(cls, argv, cwd, env, echo, preexec_fn, dimensions)\u001b[0m\n\u001b[1;32m    224\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    225\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0muse_native_pty_fork\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 226\u001b[0;31m             \u001b[0mpid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpty\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfork\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    227\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    228\u001b[0m             \u001b[0;31m# Use internal fork_pty, for Solaris\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/lib/python3.6/pty.py\u001b[0m in \u001b[0;36mfork\u001b[0;34m()\u001b[0m\n\u001b[1;32m     95\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     96\u001b[0m     \u001b[0mmaster_fd\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mslave_fd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mopenpty\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 97\u001b[0;31m     \u001b[0mpid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfork\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     98\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mpid\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mCHILD\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     99\u001b[0m         \u001b[0;31m# Establish a new session.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mOSError\u001b[0m: [Errno 12] Cannot allocate memory"
     ]
    }
   ],
   "source": [
    "# 在notebook中调用命令行工具，需要在命令前加一个 !\n",
    "#里面包含了 tag_set数据（类似于版本信息的东西） 和 signature_def数据（模型签名）\n",
    "!saved_model_cli show --dir ./keras_saved_graph --all"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "ename": "OSError",
     "evalue": "[Errno 12] Cannot allocate memory",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mOSError\u001b[0m                                   Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-13-49abf40aaddf>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mget_ipython\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msystem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'saved_model_cli show --dir ./keras_saved_graph      --tag_set serve --signature_def serving_default'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/IPython/core/interactiveshell.py\u001b[0m in \u001b[0;36msystem_piped\u001b[0;34m(self, cmd)\u001b[0m\n\u001b[1;32m   2444\u001b[0m         \u001b[0;31m# a non-None value would trigger :func:`sys.displayhook` calls.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2445\u001b[0m         \u001b[0;31m# Instead, we store the exit_code in user_ns.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2446\u001b[0;31m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0muser_ns\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'_exit_code'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msystem\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvar_expand\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcmd\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdepth\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   2447\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2448\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0msystem_raw\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcmd\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/IPython/utils/_process_posix.py\u001b[0m in \u001b[0;36msystem\u001b[0;34m(self, cmd)\u001b[0m\n\u001b[1;32m    154\u001b[0m                 \u001b[0mchild\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpexpect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mspawnb\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'-c'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcmd\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# Pexpect-U\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    155\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 156\u001b[0;31m                 \u001b[0mchild\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpexpect\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mspawn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msh\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'-c'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcmd\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# Vanilla Pexpect\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    157\u001b[0m             \u001b[0mflush\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msys\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mstdout\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mflush\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    158\u001b[0m             \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/pexpect/pty_spawn.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, command, args, timeout, maxread, searchwindowsize, logfile, cwd, env, ignore_sighup, echo, preexec_fn, encoding, codec_errors, dimensions, use_poll)\u001b[0m\n\u001b[1;32m    203\u001b[0m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'<pexpect factory incomplete>'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    204\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 205\u001b[0;31m             \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_spawn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcommand\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpreexec_fn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdimensions\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    206\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0muse_poll\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0muse_poll\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    207\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/pexpect/pty_spawn.py\u001b[0m in \u001b[0;36m_spawn\u001b[0;34m(self, command, args, preexec_fn, dimensions)\u001b[0m\n\u001b[1;32m    302\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    303\u001b[0m         self.ptyproc = self._spawnpty(self.args, env=self.env,\n\u001b[0;32m--> 304\u001b[0;31m                                      cwd=self.cwd, **kwargs)\n\u001b[0m\u001b[1;32m    305\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    306\u001b[0m         \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mptyproc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpid\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/pexpect/pty_spawn.py\u001b[0m in \u001b[0;36m_spawnpty\u001b[0;34m(self, args, **kwargs)\u001b[0m\n\u001b[1;32m    313\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m_spawnpty\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    314\u001b[0m         \u001b[0;34m'''Spawn a pty and return an instance of PtyProcess.'''\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 315\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mptyprocess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mPtyProcess\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mspawn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    316\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    317\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mforce\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mTrue\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/environment/tf_py3/lib/python3.6/site-packages/ptyprocess/ptyprocess.py\u001b[0m in \u001b[0;36mspawn\u001b[0;34m(cls, argv, cwd, env, echo, preexec_fn, dimensions)\u001b[0m\n\u001b[1;32m    224\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    225\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0muse_native_pty_fork\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 226\u001b[0;31m             \u001b[0mpid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpty\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfork\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    227\u001b[0m         \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    228\u001b[0m             \u001b[0;31m# Use internal fork_pty, for Solaris\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m/usr/lib/python3.6/pty.py\u001b[0m in \u001b[0;36mfork\u001b[0;34m()\u001b[0m\n\u001b[1;32m     95\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     96\u001b[0m     \u001b[0mmaster_fd\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mslave_fd\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mopenpty\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 97\u001b[0;31m     \u001b[0mpid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mos\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfork\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     98\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mpid\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0mCHILD\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     99\u001b[0m         \u001b[0;31m# Establish a new session.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mOSError\u001b[0m: [Errno 12] Cannot allocate memory"
     ]
    }
   ],
   "source": [
    "# 查看指定的tag_set数据  和 signature_def的数据\n",
    "# 里面的数据 表示了如何把数据传给它，以及从那里获取预测数据\n",
    "!saved_model_cli show --dir ./keras_saved_graph \\\n",
    "    --tag_set serve --signature_def serving_default"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 测试SvaedModel\n",
    "!saved_model_cli run --dir ./keras_saved_graph --tag_set serve \\\n",
    "    --signature_def serving_default \\\n",
    "    # input_expres 表示后面的字符串是个python代码表达式，能够被执行\n",
    "    # 因为上面查看到 输入的数据变量是  flatten_input\n",
    "    --input_exprs 'flatten_input=np.ones((2, 28, 28))'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['serving_default']\n"
     ]
    }
   ],
   "source": [
    "## 加载模型\n",
    "loaded_saved_model = tf.saved_model.load('./keras_saved_graph')\n",
    "## 打印模型中所有的签名\n",
    "print(list(loaded_saved_model.signatures.keys()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<tensorflow.python.saved_model.load._WrapperFunction object at 0x7f9d36a60208>\n"
     ]
    }
   ],
   "source": [
    "## 获取模型函数句柄，该句柄其实相当于是 model对象\n",
    "inference = loaded_saved_model.signatures['serving_default']\n",
    "print(inference)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'dense_2': TensorSpec(shape=(None, 10), dtype=tf.float32, name='dense_2')}\n"
     ]
    }
   ],
   "source": [
    "## 查看该函数句柄的 输出结构\n",
    "print(inference.structured_outputs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "((), {'flatten_input': TensorSpec(shape=(None, 28, 28), dtype=tf.float32, name='flatten_input')})\n"
     ]
    }
   ],
   "source": [
    "## 查看输入结构\n",
    "print(inference.structured_input_signature)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'dense_2': <tf.Tensor: shape=(1, 10), dtype=float32, numpy=\n",
      "array([[7.9263748e-07, 2.1007020e-06, 6.1471945e-07, 1.4300394e-05,\n",
      "        1.5485293e-06, 6.0877991e-03, 3.5777621e-06, 1.3541666e-02,\n",
      "        1.4261015e-04, 9.8020512e-01]], dtype=float32)>}\n",
      "tf.Tensor(\n",
      "[[7.9263748e-07 2.1007020e-06 6.1471945e-07 1.4300394e-05 1.5485293e-06\n",
      "  6.0877991e-03 3.5777621e-06 1.3541666e-02 1.4261015e-04 9.8020512e-01]], shape=(1, 10), dtype=float32)\n"
     ]
    }
   ],
   "source": [
    "## 调用函数句柄进行预测，\n",
    "## 注意，函数句柄要求的参数是一个tensor类型，因此使用tf.constant包装一下\n",
    "results = inference(tf.constant(x_test_scaled[0:1]))\n",
    "print(results)\n",
    "print(results['dense_2'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
